package com.xtwy.spike.service.impl;

import com.xtwy.spike.entity.RedPacket;
import com.xtwy.spike.entity.UserRedPacket;
import com.xtwy.spike.mapper.RedPacketMapper;
import com.xtwy.spike.mapper.UserRedPacketMapper;
import com.xtwy.spike.service.UserRedPacketService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 类的描述：
 *
 * @作者: 侯建军
 * @邮箱: 474177818@qq.com
 * @博客: https://blog.csdn.net/marquis888
 * @创建日期: 2018年12月02日  21:59
 * @版本: v1.0
 * @jdk版本使用: JDK1.8
 */
@Service
@Slf4j
public class UserRedPacketServiceImpl implements UserRedPacketService {

    @Autowired
    private UserRedPacketMapper userRedPacketMapper;
    @Autowired
    private RedPacketMapper redPacketMapper;
    //读取redis
    @Autowired
    private RedisTemplate redisTemplate;
    // 失败
    private static final int FAILED = 0;

    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int grapRedPacket(Long redPacketId, Long userId) {
        // 获取红包信息
        RedPacket redPacket = redPacketMapper.getRedPacket(redPacketId);
        int leftRedPacket = redPacket.getStock();
        // 当前小红包库存大于0
        if (leftRedPacket > 0) {
            redPacketMapper.decreaseRedPacket(redPacketId);
            log.info("剩余Stock数量:{}", leftRedPacket);
            // 生成抢红包信息
            UserRedPacket userRedPacket = new UserRedPacket();
            userRedPacket.setRedPacketId(redPacketId);
            userRedPacket.setUserId(userId);
            userRedPacket.setAmount(redPacket.getUnitAmount());
            userRedPacket.setNote("redpacket- " + redPacketId);
            // 插入抢红包信息
            int result = userRedPacketMapper.grapRedPacket(userRedPacket);
            return result;
        }
        log.info("没有红包啦.....剩余Stock数量:{}", leftRedPacket);
        // 失败返回
        return FAILED;
    }

    /**
     *
     *
     * @Title: grapRedPacketForVersion
     *
     * @Description: 乐观锁，按次数重入
     *
     * @param redPacketId
     * @param userId
     *
     * @return: int
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)
    public int grapRedPacketForVersion(Long redPacketId, Long userId) {
        for (int i = 0; i < 3; i++) {
            // 获取红包信息，注意version值
            RedPacket redPacket = redPacketMapper.getRedPacket(redPacketId);
            // 当前小红包库存大于0
            if (redPacket.getStock() > 0) {
                // 再次传入线程保存的version旧值给SQL判断，是否有其他线程修改过数据
                int update = redPacketMapper.decreaseRedPacketForVersion(redPacketId, redPacket.getVersion());
                // 如果没有数据更新，则说明其他线程已经修改过数据，则重新抢夺
                if (update == 0) {
                    continue;
                }
                // 生成抢红包信息
                UserRedPacket userRedPacket = new UserRedPacket();
                userRedPacket.setRedPacketId(redPacketId);
                userRedPacket.setUserId(userId);
                userRedPacket.setAmount(redPacket.getUnitAmount());
                userRedPacket.setNote("抢红包 " + redPacketId);
                // 插入抢红包信息
                int result = userRedPacketMapper.grapRedPacket(userRedPacket);
                return result;
            } else {
                // 一旦没有库存，则马上返回
                return FAILED;
            }
        }
        return FAILED;
    }





    @Override
    public Long grapRedPacketByRedis(Long redPacketId, Long userId) {
        // 当前抢红包用户和日期信息
        String args = userId + "-" + System.currentTimeMillis();
        Long result = null;
//        // 获取底层Redis操作对象
//        Jedis jedis = (Jedis) redisTemplate.getConnectionFactory().getConnection().getNativeConnection();
//        try {
//            // 如果脚本没有加载过，那么进行加载，这样就会返回一个sha1编码
//            if (sha1 == null) {
//                sha1 = jedis.scriptLoad(script);
//            }
//            // 执行脚本，返回结果
//            Object res = jedis.evalsha(sha1, 1, redPacketId + "", args);
//            result = (Long) res;
//            // 返回2时为最后一个红包，此时将抢红包信息通过异步保存到数据库中
//            if (result == 2) {
//                // 获取单个小红包金额
//                String unitAmountStr = jedis.hget("red_packet_" + redPacketId, "unit_amount");
//                // 触发保存数据库操作
//                Double unitAmount = Double.parseDouble(unitAmountStr);
//                redisRedPacketService.saveUserRedPacketByRedis(redPacketId, unitAmount);
//            }
//        } finally {
//            // 确保jedis顺利关闭
//            if (jedis != null && jedis.isConnected()) {
//                jedis.close();
//            }
//        }
        return result;
    }
    //用于计算并发红包挣抢后的累计金额，验证是否存在并发多读数据
    static AtomicInteger p = new AtomicInteger(0);

    /**
     *
     *
     * 乐观锁，按时间戳重入
     *
     * @Description: 乐观锁，按时间戳重入
     *
     * @param redPacketId
     * @param userId
     * @return
     *
     * @return: int
     */
    // @Override
    // @Transactional(isolation = Isolation.READ_COMMITTED, propagation =
    // Propagation.REQUIRED)
    // public int grapRedPacketForVersion(Long redPacketId, Long userId) {
    // // 获取红包信息
    // RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);
    // // 当前小红包库存大于0
    // if (redPacket.getStock() > 0) {
    // // 再次传入线程保存的version旧值给SQL判断，是否有其他线程修改过数据
    // int update = redPacketDao.decreaseRedPacketForVersion(redPacketId,
    // redPacket.getVersion());
    // // 如果没有数据更新，则说明其他线程已经修改过数据，则重新抢夺
    // if (update == 0) {
    // return FAILED;
    // }
    // // 生成抢红包信息
    // UserRedPacket userRedPacket = new UserRedPacket();
    // userRedPacket.setRedPacketId(redPacketId);
    // userRedPacket.setUserId(userId);
    // userRedPacket.setAmount(redPacket.getUnitAmount());
    // userRedPacket.setNote("redpacket- " + redPacketId);
    // // 插入抢红包信息
    // int result = userRedPacketDao.grapRedPacket(userRedPacket);
    // return result;
    // }
    // // 失败返回
    // return FAILED;
    // }
    /**
     * 乐观锁，无重入
     * */
    // @Override
    // @Transactional(isolation = Isolation.READ_COMMITTED, propagation =
    // Propagation.REQUIRED)
    // public int grapRedPacketForVersion(Long redPacketId, Long userId) {
    // // 获取红包信息
    // RedPacket redPacket = redPacketDao.getRedPacket(redPacketId);
    // // 当前小红包库存大于0
    // if (redPacket.getStock() > 0) {
    // // 再次传入线程保存的version旧值给SQL判断，是否有其他线程修改过数据
    // int update = redPacketDao.decreaseRedPacketForVersion(redPacketId,
    // redPacket.getVersion());
    // // 如果没有数据更新，则说明其他线程已经修改过数据，则重新抢夺
    // if (update == 0) {
    // return FAILED;
    // }
    // // 生成抢红包信息
    // UserRedPacket userRedPacket = new UserRedPacket();
    // userRedPacket.setRedPacketId(redPacketId);
    // userRedPacket.setUserId(userId);
    // userRedPacket.setAmount(redPacket.getUnitAmount());
    // userRedPacket.setNote("redpacket- " + redPacketId);
    // // 插入抢红包信息
    // int result = userRedPacketDao.grapRedPacket(userRedPacket);
    // return result;
    // }
    // // 失败返回
    // return FAILED;
    // }
}
